""" This file contains useful utilities """

load("@rules_shell//shell:sh_binary.bzl", "sh_binary")

def full_label(name):
    if hasattr(native, "package_relative_label"):
        return native.package_relative_label(name)
    else:
        # pre Bazel 6.1.0
        return Label(native.repository_name() + "//" + native.package_name() + ":" + name)

def runnable_binary(name, binary, foreign_cc_target, match_binary_name = False, **kwargs):
    """
    Macro that provides a wrapper script around a binary generated by a rules_foreign_cc rule that can be run using "bazel run".

    The wrapper script also facilitates the running of binaries that are dynamically linked to shared libraries also built by rules_foreign_cc. The runnable bin could be used as a tool in a dependent bazel target

    Note that this macro requires bazel 5.4.0 due to the use of the rlocationpath variable (see https://github.com/bazelbuild/bazel/issues/10923 for context)
    Also note that the macro requires the `--enable_runfiles` option to be set on Windows.

    Args:
        name: The target name
        binary: The name of the binary generated by rules_foreign_cc, should not include .exe extension
        foreign_cc_target: The target that generates the binary
        match_binary_name: True if the generated runnable file should have the same name as the provided "binary" argument. This is useful when the runnable_binary is used with tools that expect a certain filename, e.g tools like CMake and Meson expect "pkg-config" to be on the PATH
        **kwargs: Remaining keyword arguments
    """

    tags = kwargs.pop("tags", [])

    config_setting_name = name + "_windows_config_setting"

    # filegroups cannot select on constraint_values in before Bazel 5.1. Add this config_setting as a workaround. See https://github.com/bazelbuild/bazel/issues/13047
    native.config_setting(
        name = config_setting_name,
        constraint_values = [
            "@platforms//os:windows",
        ],
    )

    native.filegroup(
        name = name + "_fg",
        srcs = [foreign_cc_target],
        tags = tags + ["manual"],
        output_group = select({
            ":" + config_setting_name: binary + ".exe",
            "//conditions:default": binary,
        }),
    )

    wrapper_cmd = """
    sed s@EXECUTABLE@$(rlocationpath {name})@g $(location @rules_foreign_cc//foreign_cc/private:runnable_binary_wrapper.sh) > tmp
    cp tmp $@
    """

    fg_label = full_label(name + "_fg")

    native.genrule(
        name = name + "_wrapper",
        srcs = ["@rules_foreign_cc//foreign_cc/private:runnable_binary_wrapper.sh", name + "_fg"],
        outs = [name + "_wrapper.sh"],
        cmd = wrapper_cmd.format(name = fg_label),
        tags = tags + ["manual"],
    )

    sh_binary(
        name = binary if match_binary_name else name,
        deps = ["@bazel_tools//tools/bash/runfiles"],
        data = [name + "_fg", foreign_cc_target],
        srcs = [name + "_wrapper"],
        tags = tags + ["manual"],
        **kwargs
    )

    if match_binary_name:
        native.alias(
            name = name,
            actual = binary,
            tags = tags,
            **kwargs
        )
